#include <stdio.h>

#ifdef WIN32
#include <windows.h>
#include <tchar.h>
#else
#define _tprintf wprintf
#endif

#include <assert.h>

#include "../src/attest.h"
using namespace AllTing::Test;

#include "type.h"

int fn_testee1();

int fn_testee1()
{
	_tprintf(L"fn_testee1\n");
	return 0;
}
int fn_testee2()
{
	_tprintf(L"fn_testee2\n");
	return 0;
}
int fn_testee3()
{
	_tprintf(L"fn_testee3\n");
	return 0;
}


int test_testobject()
{
	//Test aTest(fn_testee1, L"Test C func");
	//AllTing::Test::Test* pTest = TestFactory::Instance()->Create(fn_testee1, L"Test C Func");
	AllTing::Test::Test* pTest = TestFactory::Instance()->Create(static_cast< ::Func>(&fn_testee1), L"Test C Func");

	//AllTing::Test::Test* pTest = NEW_FUNC(fn_testee1);
	pTest->Run();

	ATASSERT(0 == pTest->Error());

	return 0;
}

int test_log()
{
	String strOutput = L"Testing console output object\n";
	ATASSERT(strOutput.length() == DebugFactory::Instance()->Log(strOutput.c_str()));
	return 0;
}


int test_testcase_addremove()
{
	TestCase aTestCase(L"Default testcase");
	
	AllTing::Test::Test* pTest1 = NEW_FUNC(fn_testee1);
	AllTing::Test::Test* pTest2 = NEW_FUNC(fn_testee2);
	AllTing::Test::Test* pTest3 = NEW_FUNC(fn_testee3);

	// remove test by order
	aTestCase.Add(pTest1);
	ATASSERT(1 == aTestCase.Size());
	aTestCase.Add(pTest2);
	ATASSERT(2 == aTestCase.Size());
	aTestCase.Add(pTest3);
	ATASSERT(3 == aTestCase.Size());

	aTestCase.Run();

	aTestCase.Remove(pTest1);
	ATASSERT(2 == aTestCase.Size());
	aTestCase.Remove(pTest2);
	ATASSERT(1 == aTestCase.Size());
	aTestCase.Remove(pTest3);
	ATASSERT(0 == aTestCase.Size());

	// remove test by reverse order
	aTestCase.Add(pTest1);
	ATASSERT(1 == aTestCase.Size());
	aTestCase.Add(pTest2);
	ATASSERT(2 == aTestCase.Size());
	aTestCase.Add(pTest3);
	ATASSERT(3 == aTestCase.Size());

	aTestCase.Run();
	
	aTestCase.Remove(pTest3);
	ATASSERT(2 == aTestCase.Size());
	aTestCase.Remove(pTest2);
	ATASSERT(1 == aTestCase.Size());
	aTestCase.Remove(pTest1);
	ATASSERT(1 == aTestCase.Size());
	ATASSERT(1 == aTestCase.Size());
	ATASSERT(1 == aTestCase.Size());
	ATTRACE(L"This is a test for failed case\n");
	ATTRACE(L"Failed on %S\n", aTestCase.Name());

	return 0;
}

int test_testcase_addfunc()
{
	TestCase aTestCase(L"Default testcase");

	aTestCase.Add(TestFactory::Instance()->Create(fn_testee1, L"Test C func1"));
//	aTestCase.Add(NEW_FUNC(fn_testee1));
	aTestCase.Add(NEW_FUNC(fn_testee2));
	aTestCase.Add(NEW_FUNC(fn_testee3));

	aTestCase.Run();

	return 0;
}

int test_basic()
{
	test_testobject();
	test_log();
	test_testcase_addfunc();
	test_testcase_addremove();
	return 0;
}

class MyTestCase : public TestCase
{
public:
	MyTestCase(const Char* pszName) : TestCase(pszName), n_(0)
	{
		Add(NEW_TEST(MyTestCase::Testee1));
//		Add(new Test(static_cast<TestCase::Testee>(&MyTestCase::Testee2), String(L"MyTestCase Testee2\n")));
		Add(TestFactory::Instance()->Create(this, static_cast<Testable::Testee>(&MyTestCase::Testee2), L"MyTestCase Testee2"));
	}
	~MyTestCase()
	{
	}

	int Testee1()
	{
		_tprintf(L"Testee1 on MyTestCase\n");
		return 0;
	}
	int Testee2()
	{
		ATASSERT(n_ == 10);
		return 0;
	}
	
	virtual Bool SetUp()
	{
		n_ = 10;
		ATTRACE(L"Initialize testcase here...\r\n");
		return True;
	}

	virtual Bool TearDown()
	{
		ATTRACE(L"Uninitialize testcase here...\r\n");
		return True;
	}
protected:
	UInt32 n_;
};

int main()
{
//	INIT_TEST();

	test_basic();

	TestSuite aTestSuite(L"TestSuite");

	MyTestCase aTestCase(L"MyTestCase");

	aTestSuite.Add(&aTestCase);

	aTestSuite.Run();

//	DebugFactory::Instance()->Report();
	REPORT_TEST();

//	TestFactory::Instance()->Destroy();
	DESTROY_TEST();

	return 0;
}

